﻿#include "stdafx.h"
#include "H264_decoder.h"
#ifdef DECODE_LOG
#include "DebugUtils.h"
#endif // DEBUG

H264_decoder::H264_decoder() {
    pCodecCtx = NULL;
    pCodec = NULL;
    pFrame = NULL;
    pPacket = NULL;

    m_bInit = FALSE;

    nWidth = 1920;
    nHeight = 1080;
    nFrameSize = nWidth * nHeight * 3 / 2;
}

H264_decoder::~H264_decoder() {
    avcodec_close(pCodecCtx);
    avcodec_free_context(&pCodecCtx);
    av_frame_free(&pFrame);
    av_packet_free(&pPacket);
    pCodecCtx = NULL;
    pCodec = NULL;
    pFrame = NULL;
    pPacket = NULL;
}

BOOL H264_decoder::GetInitSts() {
    return m_bInit;
}

int H264_decoder::init(int nW, int nH) {
    nWidth = nW;
    nHeight = nH;
    nFrameSize = nWidth * nHeight * 3 / 2;
    pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);
    if (!pCodec)
        return -1;

    pCodecCtx = avcodec_alloc_context3(NULL);
    if (!pCodecCtx)
        return -1;
    pCodecCtx->thread_count = 4;

    int ret = avcodec_open2(pCodecCtx, pCodec, NULL);
    if (ret != 0)
        return -2;

    pFrame = av_frame_alloc();
    if (!pFrame)
        return -1;
    pPacket = av_packet_alloc();

    m_bInit = TRUE;
    return 0;
}

BOOL H264_decoder::DecodeFun(BYTE* pSrcBuf, int nDeLen, BYTE* pDstBuf, int& nWidth, int& nHeight) {
    BOOL bRet = FALSE;
    int nSize = 0;

#ifdef DECODE_LOG
    clock_t stop1 = clock();
#endif

    av_new_packet(pPacket, nDeLen);
    memcpy(pPacket->data, pSrcBuf, nDeLen);
    pPacket->size = nDeLen;

    int got_frame = 0;
    avcodec_decode_video2(pCodecCtx, pFrame, &got_frame, pPacket);
    if (got_frame == 1) {
    #ifdef DECODE_LOG
        char* type = NULL;
        if (pFrame->pict_type == AV_PICTURE_TYPE_I) {
            type = "I";
        } else if (pFrame->pict_type == AV_PICTURE_TYPE_B) {
            type = "B";
        } else if (pFrame->pict_type == AV_PICTURE_TYPE_P) {
            type = "P";
        } else {
            type = "?";
        }
        clock_t stop2 = clock();
        writeLog("[Decode] Frame type: %s, Frame length: %d, Phase-1: %dms, Phase-2: %dms.\n", type, nDeLen, stop1 - startTime, stop2 - stop1);
        startTime = stop2;
    #endif

        nWidth = pCodecCtx->width;
        nHeight = pCodecCtx->height;
        nSize = pCodecCtx->width * pCodecCtx->height;

        //复制一份编码
        memcpy(pDstBuf, pFrame->data[0], nSize);
        memcpy(pDstBuf + nSize, pFrame->data[1], nSize / 4);
        memcpy(pDstBuf + nSize + nSize / 4, pFrame->data[2], nSize / 4);

        bRet = TRUE;
    } else {
    #ifdef DECODE_LOG
        clock_t stop2 = clock();
        writeLog("[Decode] Failed! Frame length: %d, Phase-1: %dms, Phase-2: %dms.\n", nDeLen, stop1 - startTime, stop2 - stop1);
        startTime = stop2;
    #endif // DEBUG

    }
    av_free_packet(pPacket);

    return bRet;
}
